import Socket from "@/socket/index.js"
import cmd,{resCmdTypes} from "./cmd.js"
import {msgFilter} from "./msg.js"
import {ajax, request} from "@/utils/ajax.js"
import { getIMConfig, im_list, initTask, setIMConfig } from "@/utils/config.js"
import { getNetworkType, toast } from "../utils/util.js"
const loopCount = 3
const socketInstance = new Socket();

const heartGap = 5000;
const overtime = 30*1000;


const errEnum ={
	10020:'不合法校验',
	10021:'关闭成功',
	10022:'对方已屏蔽你的消息',
	10023:'对方未喜欢或回复你之前，最多只能发送3条文字消息',
	10024:'聊天群已解散',
	10025:'不存在的聊天群',
	10026:'您已不在该聊天群中',
	10027:'管理员已开启群禁言',
	10028:'您已被禁言',
	10029:'消息发送过于频繁'
}


export const connectEnum = {
	offline:0, 
	online:1, 
	connecting:2 
}

export default class IM {
	constructor() {
		this.userName = 'test';
		this.password = 'test';
		this.connectStatus = connectEnum.offline
		
		this.token = null; 
		this.userId = null;
		
		this.heartTimer = null; 
		
		this.loginPromise = null;
		this.logoutPromise = null;
		this.historyPromise = null 
		this.msgHandle = (res)=>{ 
			console.log(res)
		};
		this.recordsHandle =(res)=>{ 
			console.log(res)
		}
		this.offlineHandle =(res)=>{ 
			console.log(res)
		}
		this.penetrateHandle = (res) =>{ 
			console.log(res)
		}
		this.closeHandle = (res)=>{
			console.log('closeHandle',res)
		}
		this.openHandle=(res)=>{
			console.log('openHandle',res)
		}
		this.readHandle = (res) =>{
			console.log('readHandle',res)
		}
		this.onMsg =({command,code,msg,data})=>{
		   if(command==resCmdTypes.login){ 
			   if(code==10007){ 
				   this.loginPromise.resolve({code,msg,data});
			   }else if(code ==10008){ 
				   this.loginPromise.reject({code,msg,data});
			   }
		   }else if(command==resCmdTypes.chat){ 
			   this.msgHandle({code,msg,data})
		   }else if(command==resCmdTypes.penetrate){ 
			   this.penetrateHandle({code,msg,data})
		   }else if(command==resCmdTypes.records){ 
			   if(this.historyPromise){
				   clearTimeout(this.historyPromise.timer)
				   this.historyPromise.resolve({code,msg,data})
			   }
		   }else if(command==resCmdTypes.offline){ 
			   this.offlineHandle({code,msg,data})
		   }else if(command==resCmdTypes.logout){
			   this.logoutPromise&&this.logoutPromise.resolve()
		   }else if(command==resCmdTypes.read){
			   this.readHandle({code,msg,data})
		   }
		}
	
		socketInstance.onMessage(({data})=>{
			this.onMsg(JSON.parse(data))
		})
		socketInstance.onOpen((e)=>{
			this.connectStatus = connectEnum.online
			this.openHandle(e)
		})
		socketInstance.onClose((e)=>{
			this.connectStatus = connectEnum.offline
			this.closeHandle(e)
		})
	}
	async login({token,userId}){
		console.log("登陆IM模块")
		try{
			this.connectStatus = connectEnum.connecting
			this.userId = userId;
			this.token = token;
			const res = await new Promise((resolve,reject)=>{
				this.loginPromise ={
					resolve,
					reject
				}
				socketInstance.connect(`token=${token}&username=${this.userName}&password=${this.password}`).catch(reject)
			})
			console.log("IM模块链接成功")
			this.heart(); 
			uni.$emit('im_login_success')
			return res;
		}catch(e){
			console.log(e)
			this.connectStatus = connectEnum.offline
		}
	}
	async logout(){
		if(!this.token){
			throw new Error("尚未登录,无法登出")
		}
		const res = await new Promise((resolve,reject)=>{
			this.logoutPromise = {
				resolve,
				reject
			}
			socketInstance.send(cmd.logout(this.userId))
		})
		clearInterval(this.heartTimer) 
		this.connectStatus = connectEnum.offline
		this.token =null;
		this.userId = null;
		return res;
	}
	heart(){
		clearInterval(this.heartTimer) 
		this.heartTimer = setInterval(()=>{
			
			socketInstance.send(cmd.heartbeat()).catch((e)=>{
				console.log('心跳失败,尝试重连',e)
				this.login({token:this.token,userId:this.userId})
			})
		},heartGap)
	}
	oneHeart(){
		if(!this.token||!this.userId){
			return '请登录'
		}
		socketInstance.send(cmd.heartbeat()).catch((e)=>{
			console.log('心跳失败,尝试重连',e)
			this.login({token:this.token,userId:this.userId})
		})
	}
	async send(msg){
		if(!this.token){
			throw new Error("尚未登录,不能发送消息")
		}
		msg = msgFilter(msg); 
		return this.httpSend(msg)
		
	}
	async httpSend(data){
		
		try{
			const res = await ajax({
				url: '/im/message/send',
				data: data
			})
			return res
		}catch(e){
			if(!!errEnum[e.retCode]){
				throw new Error(errEnum[e.retCode])
			}else{ 
				throw new Error(e.message||e.retDesc)
			}
		}
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
	}
	createMessage({ 
		to, 
		msgType, 
		content, 
		extras,	
		chatType, 
		groupId 
	}){
		if(!this.token){
			throw new Error("尚未登录,无法创建消息")
		}
		return cmd.chatMsg({
			to,
			msgType,
			content,
			extras,
			chatType,
			groupId,
			from:this.userId
		})
	}
	async recall({msgId,to,chatType}){
		try{
			let res = null
			for (let i = 1; i <= im_list.length*loopCount; i++) {
				try{
					res = await request({
						url:`${getIMConfig().httpBase}/api/custom/message/recall`,
						header:{
							token:this.token
						},
						method:'POST',
						data:{
							recallId:msgId,
							toBizId:to,
							toBizType:chatType
						}
					})
					break;
				}catch(e){
					setIMConfig(im_list[i%im_list.length])
					if(i>=im_list.length*loopCount){
						throw e
					}
				}
			}
			const {data:{code,msg,command}} = res
			if(code==10000){ 
				return {code,msg,command}
			}else if(code==10001){ 
				return {code,msg}
			}else if(code==10019){ 
				return {code,msg}
			}else if(!!errEnum[code]){
				throw new Error(errEnum[code])
			}else{ 
				throw new Error(msg)
			}
		}catch(e){
			const {networkType} = await getNetworkType()
			if(networkType=='none'){
				throw new Error('网络连接断开，请检查网络设置')
			}else{
				throw e
			}
		}
	}
	
	async dictate({ 
		to,
		groupId,
		chatType,
		msgType,
		content,
		extras
	}){
		if(!this.token){
			throw new Error("尚未登录,无法发送指令");
		}
		const dict = cmd.penetrate({
			to,
			groupId,
			chatType,
			msgType,
			content,
			extras,
			from:this.userId
		})
		
		return this.httpSend(dict)
		
	}
	
	async read({id,to,groupId,from,chatType,createTime}){
		if(!this.token){
			throw new Error("尚未登录,无法已读消息");
		}
		const dict = cmd.read({
			userId:this.userId,
			toObjId:chatType==1?groupId:from,
			toObjType:chatType,
			msgId:id,
			msgTime:createTime
		})
		return socketInstance.send(dict)
	}
	
	async getHistory({offset,count=10,...rest}){ 
		if(this.historyPromise){
			throw new Error("正在请求,请勿重复发送")
		}
		try{
			if(!socketInstance.socketTask){
				throw new Error('尚未登录')
			}
			const msg = cmd.history({userId:this.userId,offset,count,...rest})
			await socketInstance.send(msg)
			const res = await new Promise((resolve,reject)=>{
				this.historyPromise = {
					resolve,
					reject,
					timer:setTimeout(reject,overtime)
				}
			})
			return res
		}finally{
			this.historyPromise = null
		}
	}
	
	async offline(){
		const msg = cmd.offline({userId:this.userId})
		await socketInstance.send(msg)
	}
	
	onMessage(handle){ 
		this.msgHandle = handle
	}
	onOffline(handle){
		this.offlineHandle = handle;
	}
	onPenetrate(handle){ 
		this.penetrateHandle = handle
	}
	onClose(handle){
		this.closeHandle = handle
	}
	onOpen(handle){
		this.openHandle = handle
	}
	onRead(handle){
		this.readHandle = handle
	}
}


